function http_getfile(url, filename, options)
% http_getfile  - retrieve a URL into a local file
%
% to download a file, this method uses http_get with several
% options
%
% FORMAT:       http_getfile(url, filename [,options])
%
% Input fields:
%
%       url         complete URL to the file to download
%       filename    name of local file to write
%       options     a struct with any of the following options
%        .chunk     size of chunks (if not given, 1/50 of length)
%        .progress  show progress (only works for given chunk)
%        .timeout   number of seconds for timeout (only Linux!)
%
% The chunk option only works for static content (i.e. when the
% webserver accepts Range: requests to that URL.
%
% See also http_get.

% Version:  v0.7f
% Build:    8110521
% Date:     Nov-05 2008, 9:00 PM CET
% Author:   Jochen Weber, SCAN Unit, Columbia University, NYC, NY, USA
% URL/Info: http://wiki.brainvoyager.com/BVQXtools

% enough arguments ?
if nargin < 2
    error( ...
        'BVQXtools:TooFewArguments',...
        'Too few arguments. Try ''help %s''.',...
        mfilename ...
    );
end

% check URL and filename
if ~ischar(url) || ...
   ~ischar(filename)
    error( ...
        'BVQXtools:BadArgument',...
        'Bad argument.' ...
    );
end

% check options
if nargin < 3 || ...
  ~isstruct(options)
    options = struct('EMPTY', 1);
end

% parse options
if isfield(options,'progress')
    doprogress = 1;
else
    doprogress = 0;
end

% get header first
hgopts = options;
hgopts.head = 1;
[s{1:3}] = http_get(url,hgopts);
h = s{2};
s = s{3};

% only proceed on HTTP 200 OK
if s ~= 200
    error( ...
        'BVQXtools:HTTPError',...
        'HTTP server response code: %d',...
        s ...
    );
end

% split header at End-Header
[h, hl] = splittocell([h char([13, 10]) 'End-Header: 1' char([13, 10])], ...
	char([13, 10]), 1);

% check file writability
ofp = fopen(filename, 'w');
if ofp < 1
    error( ...
        'BVQXtools:FileNotWritable',...
        'Couldn''t write local output file.' ...
    );
end

% server accepts range?
accept_rangel = regexpi(h, '^accept.?ranges\:\s+');
for lc = 1:hl
    if ~isempty(accept_rangel{lc})
        break;
    end
end
if lc < hl
    accept_range = 1;
else
    accept_range = 0;
end

% content length
content_lengthl = regexpi(h, '^content.?length\:\s+');
for lc = 1:hl
    if ~isempty(content_lengthl{lc})
        break;
    end
end
if lc <hl
    content_lengthp = regexpi(h{lc},'\s+(\d+)$');
    if ~isempty(content_lengthp)
        content_length = str2double(h{lc}(content_lengthp(1):end));
    else
        content_length = 0;
    end
end

% chunking available and meaningful
if accept_range && ...
    content_length > 262144

    % for default cases
    if ~isfield(options, 'chunk') || ...
        isempty(options.chunk) || ...
       ~isnumeric(options.chunk) || ...
        isnan(options.chunk(1)) || ...
        isinf(options.chunk(1)) || ...
        options.chunk(1) == 1
        chunk = floor((content_length / 20) + 1);

    % otherwise
    else
        % chunk size
        if options.chunk(1) > 511
            chunk = floor(options.chunk(1) + 0.999999);

        % or chunk number
        else
            chunk = floor((content_length / options.chunk(1)) + 1);
        end
    end

    % chunk min size is yet 4096
    if chunk < 16384
        chunk = 16384;
    end

    % and max the content_length
    if chunk >= content_length
        chunk = 0;
    end

% otherwise no chunking
else
    chunk = 0;
end

% for chunking
if chunk > 0

    % show progress?
    if doprogress

        % get nice URL
        durl = regexprep(url, 'http://', '', 'ignorecase');

        % get filename of remote file
        if ispc
            durl = strrep(durl, '/', filesep);
        end
        [durlext{1:3}] = fileparts(durl);
        durl = durlext{2};
        durlext = durlext{3};

        % show initial information
        disp(['Retrieving ''' durl durlext ''' into local file ''' filename ''' ...']);
        disp(['Total file size: ' num2str(content_length) ' bytes']);

        % init count progress
        progresscount(content_length, 2, 20, '.');
    end

    % for chunksize up to content_length-1
    for cc = 0:chunk:(content_length-1)

        % set range
        options.range = [cc, min(cc+chunk-1, content_length)];

        % append http_get result
        fwrite(ofp, http_get(url, options), 'uchar');

        % progress?
        if doprogress
            progresscount(cc);
        end
    end

    % finish progress count
    progresscount(content_length);

% no chunks, just write file
else
    fwrite(ofp, http_get(url, options), 'uchar');
end

% close file
fclose(ofp);
